import hashlib
from math import floor
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import default_rng

from complex_PLM.chart import showChart_2


def piecewise_logistic_map(x, r, num_segments):
    """分段 Logistic 映射函数
    x:状态值
    num_segments：迭代分段数
    """
    segment_length = 1.0 / num_segments
    for i in range(num_segments):
        left_segment = i * segment_length
        right_segment = (i + 1) * segment_length
        if left_segment < x < right_segment:
            if i % 2 == 0:
                x = num_segments * num_segments * r * (x - left_segment) * (right_segment - x)
            else:
                x = 1 - (num_segments * num_segments * r * (x - left_segment) * (right_segment - x))
            break
        elif x == i / num_segments and x != 1:
            x = x + 1.0 / (num_segments * 100)
            break
        elif x == 1:
            x = x - 1.0 / (num_segments * 100)
            break
    return x


def xor_binary_arrays(arr1, arr2):
    """密钥流异或操作
    arr1，arr2两个混沌映射产生的密钥流
    """
    # 将小数随机数组转换为整数数组
    int_arr1 = (np.array(arr1) * (2 ** 64)).astype(np.uint64)
    int_arr2 = (np.array(arr2) * (2 ** 64)).astype(np.uint64)

    # 执行异或操作
    result = np.bitwise_xor(int_arr1, int_arr2)

    # 将结果转换回小数数组
    result_decimal = result / (2 ** 64)

    return result_decimal


def restock_r(r, x):
    """控制参数r的迭代更新函数
    r:前一个r
    x:前一个x
    """
    a, b = 2, 4.0
    r = (a + (b - a) * (r - a + x) % (b - a)) % b
    return r


def PRNG_Cplx_T(x0,y0, num_segments_1,num_segments_2, r1, r2, key_len, is_int):
    """密钥流产生器
    num_segments：迭代分段数
    x0:初始值
    r:映射控制参数
    is_int：是否输出整数序列
    key_len：生成密钥流长度
    N0：前1200个状态值舍去
    """
    N0 = 1200
    x = x0
    y = y0
    stream_1 = []
    stream_2 = []
    for j in range(N0 + key_len):
        x = piecewise_logistic_map(x, r1, num_segments_1)
        y = piecewise_logistic_map(y, r2, num_segments_2)
        r1 = restock_r(r1, x)
        r2 = restock_r(r2, y)
        if j >= N0:
            stream_1.append(y)
            stream_2.append(x)
    r_stream = xor_binary_arrays(stream_1, stream_2)
    if is_int:
        r_stream = [floor(i * 1e14) % 256 for i in r_stream]
    return r_stream

def PRNG_Cplx(seed, num_segments, key_len, is_int, r=4.0):
    """密钥流产生器
    seed；密钥种子
    num_segments：迭代分段数
    x0:初始值
    r:映射控制参数
    is_int：是否输出整数序列
    key_len：生成密钥流长度
    N0：前1200个状态值舍去
    """
    N0 = 1200
    # x = key_to_hash(seed)
    x = seed
    stream_1 = []
    stream_2 = []
    for j in range(N0 + key_len):
        y = np.mod(r * x * (1 - x), 1)
        x = piecewise_logistic_map(x, r, num_segments)
        # t = xor(decimal_to_binary(x), decimal_to_binary(y))
        r = restock_r(r, x)
        if j >= N0:
            stream_1.append(y)
            stream_2.append(x)
    r_stream = xor_binary_arrays(stream_1, stream_2)
    if is_int:
        r_stream = [floor(i * 1e14) % 256 for i in r_stream]
    return r_stream


#  密钥获取hash函数
#  seed_str：密钥，用于初始化参数
def key_to_hash(seed):
    """密钥映射系统初始值函数
    seed：密钥key
    """
    # 计算字符串的哈希值
    sha256 = hashlib.sha256(seed.encode()).digest()
    # 使用哈希值作为种子
    rng = default_rng(int.from_bytes(sha256, "big"))
    # 生成随机数
    r = rng.random()
    # 保留两位小数
    r = np.round(r, decimals=2)
    # 输出结果
    return r

